--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Commit 98a5dd7c50d2338400df0cf0fc8175930d83cfde
Parents : 0ae5f2b
Author : Ivan <e46112d44649266d71fe2193e00a4710>
Signature : T66BB85Valid, signed by author
Date : 2026-07-19T15:36:25-05:00
feat: fix NetworkVisualiserToolbar with custom engine selection menu and improved styling, including localization updates for renderer options
Changes
12 files changed, 212 insertions(+), 43 deletions(-)
Diff
diff --git a/meshchatx.rsm b/meshchatx.rsm
index e3194aba..33582c11 100644
Binary files a/meshchatx.rsm and b/meshchatx.rsm differ
diff --git a/meshchatx/src/frontend/components/network-visualiser/internal/NetworkVisualiserToolbar.vue b/meshchatx/src/frontend/components/network-visualiser/internal/NetworkVisualiserToolbar.vue
index f0a0cb98..91e490ff 100644
--- a/meshchatx/src/frontend/components/network-visualiser/internal/NetworkVisualiserToolbar.vue
+++ b/meshchatx/src/frontend/components/network-visualiser/internal/NetworkVisualiserToolbar.vue
@@ -5,7 +5,7 @@
class="absolute top-2 left-2 right-2 sm:top-4 sm:left-4 sm:right-4 z-10 flex flex-col sm:flex-row gap-2 pointer-events-none"
>
<div
- class="pointer-events-auto border border-gray-200/50 dark:border-zinc-800/50 bg-white/90 dark:bg-zinc-900/90 rounded-2xl overflow-hidden w-full sm:min-w-[280px] sm:w-auto transition-all duration-300"
+ class="pointer-events-auto border border-gray-200/50 dark:border-zinc-800/50 bg-white/90 dark:bg-zinc-900/90 rounded-2xl overflow-hidden w-full sm:w-[280px] sm:max-w-[280px] transition-all duration-300"
>
<div
class="flex items-center px-4 sm:px-5 py-3 sm:py-4 cursor-pointer hover:bg-gray-50/50 dark:hover:bg-zinc-800/50 transition-colors"
@@ -52,30 +52,67 @@
<div class="grid grid-cols-2 gap-2">
<div
- class="rounded-xl px-3 py-2 border border-gray-100 dark:border-zinc-700/50 bg-gray-50/60 dark:bg-zinc-800/40"
+ class="relative min-w-0 rounded-xl px-3 py-2 border border-gray-100 dark:border-zinc-700/50 bg-gray-50/60 dark:bg-zinc-800/40"
:title="engineSelectTitle"
>
- <label
- for="visualiser-engine-select"
- class="text-[10px] font-bold text-gray-500 dark:text-zinc-500 uppercase tracking-wider mb-0.5 block"
+ <div
+ class="text-[10px] font-bold text-gray-500 dark:text-zinc-500 uppercase tracking-wider mb-0.5"
>
{{ $t("visualiser.engine") }}
- </label>
- <select
+ </div>
+ <button
id="visualiser-engine-select"
- class="w-full bg-transparent text-xs font-bold truncate border-0 p-0 pr-5 focus:outline-hidden focus:ring-0 cursor-pointer"
+ type="button"
+ class="flex w-full min-w-0 items-center gap-1 bg-transparent text-left text-xs font-bold focus:outline-hidden focus-visible:ring-1 focus-visible:ring-blue-500/50 rounded"
:class="engineSelectClass"
- :value="preferredRenderer"
:aria-label="$t('visualiser.engine')"
- @change="onEngineSelectChange"
+ :aria-expanded="engineMenuOpen ? 'true' : 'false'"
+ aria-haspopup="listbox"
+ @click.stop="toggleEngineMenu"
>
- <option value="auto">{{ $t("visualiser.renderer_option_auto") }}</option>
- <option value="webgl">{{ $t("visualiser.renderer_option_webgl") }}</option>
- <option value="vis">{{ $t("visualiser.renderer_option_vis") }}</option>
- </select>
+ <span class="min-w-0 flex-1 truncate">{{ engineTriggerLabel }}</span>
+ <MaterialDesignIcon
+ icon-name="chevron-down"
+ class="w-3.5 h-3.5 shrink-0 text-gray-400 transition-transform duration-200"
+ :class="{ 'rotate-180': engineMenuOpen }"
+ />
+ </button>
+ <Teleport to="body">
+ <div
+ v-if="engineMenuOpen"
+ ref="engineMenuPanel"
+ v-click-outside="closeEngineMenu"
+ class="fixed z-200 w-56 overflow-hidden rounded-xl border border-gray-200 bg-white shadow-lg dark:border-zinc-700 dark:bg-zinc-900"
+ :style="engineMenuStyle"
+ role="listbox"
+ :aria-label="$t('visualiser.engine')"
+ >
+ <button
+ v-for="opt in engineOptions"
+ :key="opt.value"
+ type="button"
+ role="option"
+ class="flex w-full items-center justify-between gap-2 px-3 py-2.5 text-left text-xs font-semibold transition-colors hover:bg-gray-100 dark:hover:bg-zinc-800"
+ :class="
+ preferredRenderer === opt.value
+ ? 'bg-blue-50 text-blue-700 dark:bg-blue-950/40 dark:text-blue-300'
+ : 'text-gray-800 dark:text-zinc-100'
+ "
+ :aria-selected="preferredRenderer === opt.value ? 'true' : 'false'"
+ @click.stop="selectEngine(opt.value)"
+ >
+ <span class="min-w-0 flex-1">{{ opt.label }}</span>
+ <MaterialDesignIcon
+ v-if="preferredRenderer === opt.value"
+ icon-name="check"
+ class="w-4 h-4 shrink-0"
+ />
+ </button>
+ </div>
+ </Teleport>
</div>
<div
- class="rounded-xl px-3 py-2 border border-gray-100 dark:border-zinc-700/50 bg-gray-50/60 dark:bg-zinc-800/40"
+ class="min-w-0 rounded-xl px-3 py-2 border border-gray-100 dark:border-zinc-700/50 bg-gray-50/60 dark:bg-zinc-800/40"
>
<div
class="text-[10px] font-bold text-gray-500 dark:text-zinc-500 uppercase tracking-wider mb-0.5"
@@ -227,8 +264,11 @@
<script>
import Toggle from "../../forms/Toggle.vue";
import MaterialDesignIcon from "../../MaterialDesignIcon.vue";
+import { clampFloatingToViewport } from "../../../js/clampFloatingToViewport.js";
import { HOP_SLIDER_POS_ALL, hopSliderPosToMaxHops, hopMaxHopsToSliderPos } from "./hopMaxFilterSliderMap.js";
+const ENGINE_VALUES = ["auto", "webgl", "vis"];
+
export default {
name: "NetworkVisualiserToolbar",
components: { Toggle, MaterialDesignIcon },
@@ -253,7 +293,7 @@ export default {
type: String,
default: "auto",
validator(v) {
- return ["auto", "webgl", "vis"].includes(v);
+ return ENGINE_VALUES.includes(v);
},
},
engineMode: {
@@ -277,6 +317,8 @@ export default {
data() {
return {
hopMaxInputDraft: null,
+ engineMenuOpen: false,
+ engineMenuPosition: null,
};
},
computed: {
@@ -295,6 +337,18 @@ export default {
if (this.hopMaxFilter === null) return this.$t("visualiser.all");
return String(this.hopMaxFilter);
},
+ engineOptions() {
+ return [
+ { value: "auto", label: this.$t("visualiser.renderer_option_auto") },
+ { value: "webgl", label: this.$t("visualiser.renderer_option_webgl") },
+ { value: "vis", label: this.$t("visualiser.renderer_option_vis") },
+ ];
+ },
+ engineTriggerLabel() {
+ if (this.preferredRenderer === "webgl") return this.$t("visualiser.renderer_option_webgl_short");
+ if (this.preferredRenderer === "vis") return this.$t("visualiser.renderer_option_vis_short");
+ return this.$t("visualiser.renderer_option_auto_short");
+ },
engineSelectTitle() {
if (this.engineMode === "webgl") return this.$t("visualiser.engine_webgl_hint");
if (this.engineMode === "wasm") return this.$t("visualiser.engine_wasm_hint");
@@ -312,13 +366,65 @@ export default {
if (!Number.isFinite(n) || n <= 0) return "--";
return String(Math.round(n));
},
+ engineMenuStyle() {
+ if (!this.engineMenuPosition) return {};
+ const style = {
+ left: `${this.engineMenuPosition.left}px`,
+ top: `${this.engineMenuPosition.top}px`,
+ };
+ if (this.engineMenuPosition.maxHeight != null) {
+ style.maxHeight = `${this.engineMenuPosition.maxHeight}px`;
+ style.overflowY = "auto";
+ }
+ return style;
+ },
+ },
+ watch: {
+ isShowingControls(open) {
+ if (!open) this.closeEngineMenu();
+ },
+ },
+ beforeUnmount() {
+ this.closeEngineMenu();
},
methods: {
- onEngineSelectChange(e) {
- const next = e?.target?.value;
- if (next === "auto" || next === "webgl" || next === "vis") {
- this.$emit("update:preferredRenderer", next);
+ toggleEngineMenu() {
+ if (this.engineMenuOpen) {
+ this.closeEngineMenu();
+ return;
+ }
+ this.openEngineMenu();
+ },
+ openEngineMenu() {
+ this.engineMenuOpen = true;
+ this.$nextTick(() => this.positionEngineMenu());
+ },
+ closeEngineMenu() {
+ this.engineMenuOpen = false;
+ this.engineMenuPosition = null;
+ },
+ positionEngineMenu() {
+ const trigger = this.$el?.querySelector?.("#visualiser-engine-select");
+ if (!trigger) return;
+ const rect = trigger.getBoundingClientRect();
+ this.engineMenuPosition = {
+ left: Math.max(8, rect.left),
+ top: rect.bottom + 6,
+ maxHeight: null,
+ };
+ this.$nextTick(() => {
+ const panel = this.$refs.engineMenuPanel;
+ if (!panel) return;
+ const pr = panel.getBoundingClientRect();
+ const { left, top, maxHeight } = clampFloatingToViewport(pr.left, pr.top, pr.width, pr.height);
+ this.engineMenuPosition = { left, top, maxHeight };
+ });
+ },
+ selectEngine(value) {
+ if (ENGINE_VALUES.includes(value)) {
+ this.$emit("update:preferredRenderer", value);
}
+ this.closeEngineMenu();
},
onHopSliderInput(e) {
const v = hopSliderPosToMaxHops(Number(e.target.value));
diff --git a/meshchatx/src/frontend/locales/de.json b/meshchatx/src/frontend/locales/de.json
index a44b2f00..4e8dd4fb 100644
--- a/meshchatx/src/frontend/locales/de.json
+++ b/meshchatx/src/frontend/locales/de.json
@@ -3466,6 +3466,9 @@
"engine_webgl_hint": "Graph, Layout und Zeichenpuffer laufen in Go-WebAssembly. Pixel werden mit WebGL2 gezeichnet",
"renderer_title": "Darstellung",
"renderer_desc": "Auto bevorzugt WebGL mit WASM, falls verfügbar, und wechselt sonst zu vis-network. Für Debugging oder ältere GPUs kann ein Pfad erzwungen werden.",
+ "renderer_option_auto_short": "Auto",
+ "renderer_option_webgl_short": "WebGL",
+ "renderer_option_vis_short": "Canvas",
"renderer_option_auto": "Auto (WebGL wenn verfügbar)",
"renderer_option_webgl": "WebGL + WASM",
"renderer_option_vis": "vis-network (Canvas)",
diff --git a/meshchatx/src/frontend/locales/en.json b/meshchatx/src/frontend/locales/en.json
index 5b7d297e..2474d417 100644
--- a/meshchatx/src/frontend/locales/en.json
+++ b/meshchatx/src/frontend/locales/en.json
@@ -1971,6 +1971,9 @@
"description": "Graph of discovered nodes and links.",
"renderer_title": "Renderer",
"renderer_desc": "Auto prefers WebGL with WASM when available, then falls back to vis-network. Force a path for debugging or older GPUs.",
+ "renderer_option_auto_short": "Auto",
+ "renderer_option_webgl_short": "WebGL",
+ "renderer_option_vis_short": "Canvas",
"renderer_option_auto": "Auto (WebGL when available)",
"renderer_option_webgl": "WebGL + WASM",
"renderer_option_vis": "vis-network (canvas)",
diff --git a/meshchatx/src/frontend/locales/es.json b/meshchatx/src/frontend/locales/es.json
index aeb4328f..b470f7e2 100644
--- a/meshchatx/src/frontend/locales/es.json
+++ b/meshchatx/src/frontend/locales/es.json
@@ -2040,6 +2040,9 @@
"engine_webgl_hint": "El grafo, el layout y los buffers de dibujo se ejecutan en Go WebAssembly. Los píxeles se dibujan con WebGL2",
"renderer_title": "Renderizador",
"renderer_desc": "Auto prefiere WebGL con WASM cuando está disponible y, si no, usa vis-network. Puedes forzar una ruta para depurar o GPUs antiguas.",
+ "renderer_option_auto_short": "Auto",
+ "renderer_option_webgl_short": "WebGL",
+ "renderer_option_vis_short": "Canvas",
"renderer_option_auto": "Auto (WebGL si está disponible)",
"renderer_option_webgl": "WebGL + WASM",
"renderer_option_vis": "vis-network (canvas)",
diff --git a/meshchatx/src/frontend/locales/fi.json b/meshchatx/src/frontend/locales/fi.json
index b4a59548..fdad15ef 100644
--- a/meshchatx/src/frontend/locales/fi.json
+++ b/meshchatx/src/frontend/locales/fi.json
@@ -2040,6 +2040,9 @@
"engine_webgl_hint": "Kaavio, asettelu ja piirtopuskurit ajetaan Go WebAssemblyssa. Pikselit piirretään WebGL2:lla",
"renderer_title": "Renderöijä",
"renderer_desc": "Auto suosii WebGL+WASM:ia kun se on saatavilla ja siirtyy muuten vis-networkiin. Voit pakottaa polun debuggaukseen tai vanhoille GPU:ille.",
+ "renderer_option_auto_short": "Auto",
+ "renderer_option_webgl_short": "WebGL",
+ "renderer_option_vis_short": "Canvas",
"renderer_option_auto": "Auto (WebGL jos saatavilla)",
"renderer_option_webgl": "WebGL + WASM",
"renderer_option_vis": "vis-network (canvas)",
diff --git a/meshchatx/src/frontend/locales/fr.json b/meshchatx/src/frontend/locales/fr.json
index 2c786a40..fa6e5454 100644
--- a/meshchatx/src/frontend/locales/fr.json
+++ b/meshchatx/src/frontend/locales/fr.json
@@ -2040,6 +2040,9 @@
"engine_webgl_hint": "Le graphe, le layout et les buffers de dessin s'exécutent en Go WebAssembly. Les pixels sont dessinés avec WebGL2",
"renderer_title": "Moteur de rendu",
"renderer_desc": "Auto préfère WebGL avec WASM lorsqu'il est disponible, sinon bascule vers vis-network. Vous pouvez forcer un chemin pour le débogage ou les anciens GPU.",
+ "renderer_option_auto_short": "Auto",
+ "renderer_option_webgl_short": "WebGL",
+ "renderer_option_vis_short": "Canvas",
"renderer_option_auto": "Auto (WebGL si disponible)",
"renderer_option_webgl": "WebGL + WASM",
"renderer_option_vis": "vis-network (canvas)",
diff --git a/meshchatx/src/frontend/locales/it.json b/meshchatx/src/frontend/locales/it.json
index ffe57b73..eb83ff3e 100644
--- a/meshchatx/src/frontend/locales/it.json
+++ b/meshchatx/src/frontend/locales/it.json
@@ -2092,6 +2092,9 @@
"engine_webgl_hint": "Grafo, layout e buffer di disegno vengono eseguiti in Go WebAssembly. I pixel sono disegnati con WebGL2",
"renderer_title": "Motore di rendering",
"renderer_desc": "Auto preferisce WebGL con WASM quando disponibile, altrimenti passa a vis-network. Puoi forzare un percorso per il debug o GPU datate.",
+ "renderer_option_auto_short": "Auto",
+ "renderer_option_webgl_short": "WebGL",
+ "renderer_option_vis_short": "Canvas",
"renderer_option_auto": "Auto (WebGL se disponibile)",
"renderer_option_webgl": "WebGL + WASM",
"renderer_option_vis": "vis-network (canvas)",
diff --git a/meshchatx/src/frontend/locales/nl.json b/meshchatx/src/frontend/locales/nl.json
index 4c8a14ef..1ec3a8b7 100644
--- a/meshchatx/src/frontend/locales/nl.json
+++ b/meshchatx/src/frontend/locales/nl.json
@@ -2040,6 +2040,9 @@
"engine_webgl_hint": "Grafiek, layout en tekenbuffers draaien in Go WebAssembly. Pixels worden met WebGL2 getekend",
"renderer_title": "Weergave",
"renderer_desc": "Auto prefereert WebGL met WASM indien beschikbaar en valt anders terug op vis-network. Forceer een pad voor debug of oudere GPU's.",
+ "renderer_option_auto_short": "Auto",
+ "renderer_option_webgl_short": "WebGL",
+ "renderer_option_vis_short": "Canvas",
"renderer_option_auto": "Auto (WebGL indien beschikbaar)",
"renderer_option_webgl": "WebGL + WASM",
"renderer_option_vis": "vis-network (canvas)",
diff --git a/meshchatx/src/frontend/locales/ru.json b/meshchatx/src/frontend/locales/ru.json
index 3672a55a..f0ba44ca 100644
--- a/meshchatx/src/frontend/locales/ru.json
+++ b/meshchatx/src/frontend/locales/ru.json
@@ -3466,6 +3466,9 @@
"engine_webgl_hint": "Граф, раскладка и буферы отрисовки выполняются в Go WebAssembly. Пиксели рисуются через WebGL2",
"renderer_title": "Рендерер",
"renderer_desc": "Авто предпочитает WebGL с WASM при наличии и иначе переходит на vis-network. Можно принудительно выбрать путь для отладки или старых GPU.",
+ "renderer_option_auto_short": "Авто",
+ "renderer_option_webgl_short": "WebGL",
+ "renderer_option_vis_short": "Canvas",
"renderer_option_auto": "Авто (WebGL если доступен)",
"renderer_option_webgl": "WebGL + WASM",
"renderer_option_vis": "vis-network (canvas)",
diff --git a/meshchatx/src/frontend/locales/zh.json b/meshchatx/src/frontend/locales/zh.json
index 0efcffa8..a8e064f8 100644
--- a/meshchatx/src/frontend/locales/zh.json
+++ b/meshchatx/src/frontend/locales/zh.json
@@ -2040,6 +2040,9 @@
"engine_webgl_hint": "图构建、布局与绘制缓冲在 Go WebAssembly 中运行。像素由 WebGL2 绘制",
"renderer_title": "渲染器",
"renderer_desc": "自动在可用时优先使用 WebGL+WASM,否则回退到 vis-network。可强制选择以便调试或兼容旧 GPU。",
+ "renderer_option_auto_short": "自动",
+ "renderer_option_webgl_short": "WebGL",
+ "renderer_option_vis_short": "Canvas",
"renderer_option_auto": "自动(可用时使用 WebGL)",
"renderer_option_webgl": "WebGL + WASM",
"renderer_option_vis": "vis-network(canvas)",
diff --git a/tests/frontend/NetworkVisualiserToolbar.test.js b/tests/frontend/NetworkVisualiserToolbar.test.js
index 5f2be519..4397cd3d 100644
--- a/tests/frontend/NetworkVisualiserToolbar.test.js
+++ b/tests/frontend/NetworkVisualiserToolbar.test.js
@@ -1,10 +1,17 @@
-import { mount } from "@vue/test-utils";
-import { describe, it, expect } from "vitest";
+import { mount, flushPromises } from "@vue/test-utils";
+import { describe, it, expect, afterEach } from "vitest";
import NetworkVisualiserToolbar from "@/components/network-visualiser/internal/NetworkVisualiserToolbar.vue";
describe("NetworkVisualiserToolbar", () => {
- const mountToolbar = (props = {}) =>
- mount(NetworkVisualiserToolbar, {
+ let wrapper;
+
+ afterEach(() => {
+ wrapper?.unmount();
+ wrapper = null;
+ });
+
+ const mountToolbar = (props = {}) => {
+ wrapper = mount(NetworkVisualiserToolbar, {
props: {
isShowingControls: true,
nodeCount: 12,
@@ -20,46 +27,74 @@ describe("NetworkVisualiserToolbar", () => {
mocks: { $t: (k, v) => (v ? `${k}:${JSON.stringify(v)}` : k) },
stubs: {
Toggle: true,
+ Teleport: true,
MaterialDesignIcon: {
props: ["iconName"],
template: `<span class="mdi-stub" :data-icon="iconName"></span>`,
},
},
+ directives: {
+ "click-outside": {
+ mounted() {},
+ unmounted() {},
+ },
+ },
},
+ attachTo: document.body,
});
+ return wrapper;
+ };
+
+ it("keeps the control panel at a fixed sm width class", () => {
+ const w = mountToolbar();
+ const panel = w.find(".pointer-events-auto.border");
+ expect(panel.classes()).toContain("sm:w-[280px]");
+ expect(panel.classes()).toContain("sm:max-w-[280px]");
+ expect(panel.classes()).not.toContain("sm:w-auto");
+ expect(panel.classes()).not.toContain("sm:min-w-[280px]");
+ });
- it("shows engine select and FPS", () => {
- const wrapper = mountToolbar();
- const select = wrapper.find("#visualiser-engine-select");
- expect(select.exists()).toBe(true);
- expect(select.element.value).toBe("auto");
- expect(wrapper.text()).toContain("58");
- expect(wrapper.text()).toContain("visualiser.fps");
- expect(wrapper.text()).toContain("visualiser.renderer_option_webgl");
- expect(wrapper.text()).toContain("visualiser.renderer_option_vis");
+ it("shows themed engine trigger and FPS without a native select", () => {
+ const w = mountToolbar();
+ expect(w.find("select").exists()).toBe(false);
+ const trigger = w.find("#visualiser-engine-select");
+ expect(trigger.exists()).toBe(true);
+ expect(trigger.element.tagName).toBe("BUTTON");
+ expect(trigger.text()).toContain("visualiser.renderer_option_auto_short");
+ expect(w.text()).toContain("58");
+ expect(w.text()).toContain("visualiser.fps");
});
- it("emits preferred renderer when engine select changes", async () => {
- const wrapper = mountToolbar({ preferredRenderer: "auto", engineMode: "webgl" });
- const select = wrapper.find("#visualiser-engine-select");
- await select.setValue("webgl");
- expect(wrapper.emitted("update:preferredRenderer")?.[0]).toEqual(["webgl"]);
- await select.setValue("vis");
- expect(wrapper.emitted("update:preferredRenderer")?.[1]).toEqual(["vis"]);
+ it("opens custom engine menu and emits preferred renderer", async () => {
+ const w = mountToolbar({ preferredRenderer: "auto", engineMode: "webgl" });
+ await w.find("#visualiser-engine-select").trigger("click");
+ await flushPromises();
+ expect(w.find('[role="listbox"]').exists()).toBe(true);
+ expect(w.text()).toContain("visualiser.renderer_option_webgl");
+ expect(w.text()).toContain("visualiser.renderer_option_vis");
+
+ const options = w.findAll('[role="option"]');
+ expect(options.length).toBe(3);
+ await options[1].trigger("click");
+ expect(w.emitted("update:preferredRenderer")?.[0]).toEqual(["webgl"]);
+ expect(w.find('[role="listbox"]').exists()).toBe(false);
});
- it("styles select from active engine mode", () => {
+ it("styles trigger from active engine mode", () => {
const webgl = mountToolbar({ engineMode: "webgl", preferredRenderer: "webgl", fps: 60 });
expect(webgl.find("#visualiser-engine-select").classes().join(" ")).toContain("text-sky-600");
+ expect(webgl.find("#visualiser-engine-select").text()).toContain("visualiser.renderer_option_webgl_short");
+ webgl.unmount();
const fallback = mountToolbar({ engineMode: "fallback", preferredRenderer: "vis", fps: 0 });
expect(fallback.find("#visualiser-engine-select").classes().join(" ")).toContain("text-amber-600");
+ expect(fallback.find("#visualiser-engine-select").text()).toContain("visualiser.renderer_option_vis_short");
expect(fallback.text()).toContain("--");
});
it("uses MDI magnify for search and refresh for update button", () => {
- const wrapper = mountToolbar({ isUpdating: false, isLoading: false });
- const icons = wrapper.findAll(".mdi-stub").map((n) => n.attributes("data-icon"));
+ const w = mountToolbar({ isUpdating: false, isLoading: false });
+ const icons = w.findAll(".mdi-stub").map((n) => n.attributes("data-icon"));
expect(icons).toContain("magnify");
expect(icons).toContain("refresh");
expect(icons).not.toContain(undefined);
@@ -70,6 +105,7 @@ describe("NetworkVisualiserToolbar", () => {
const autoIcons = autoBusy.findAll(".mdi-stub").map((n) => n.attributes("data-icon"));
expect(autoIcons).toContain("refresh");
expect(autoIcons).not.toContain("loading");
+ autoBusy.unmount();
const manualBusy = mountToolbar({ isUpdating: true, isLoading: true });
const manualIcons = manualBusy.findAll(".mdi-stub").map((n) => n.attributes("data-icon"));
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────